﻿using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Lsa
{
    [StructLayout(LayoutKind.Sequential)]
    public struct LSA_UNICODE_STRING
    {
        public UInt16 Length;
        public UInt16 MaximumLength;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string Buffer;
    }

    public struct LSA_ENUMERATION_INFORMATION
    {
        public IntPtr Sid;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LSA_OBJECT_ATTRIBUTES
    {
        public UInt32 Length;
        public IntPtr RootDirectory;
        public UInt32 Attributes;
        public LSA_UNICODE_STRING ObjectName;
        public IntPtr SecurityDescriptor;
        public IntPtr SecurityQualityOfService;
    }

    [Flags]
    internal enum LsaAccessPolicy : uint
    {
        POLICY_VIEW_LOCAL_INFORMATION = 0x00000001,
        POLICY_VIEW_AUDIT_INFORMATION = 0x00000002,
        POLICY_GET_PRIVATE_INFORMATION = 0x00000004,
        POLICY_TRUST_ADMIN = 0x00000008,
        POLICY_CREATE_ACCOUNT = 0x00000010,
        POLICY_CREATE_SECRET = 0x00000020,
        POLICY_CREATE_PRIVILEGE = 0x00000040,
        POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080,
        POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100,
        POLICY_AUDIT_LOG_ADMIN = 0x00000200,
        POLICY_SERVER_ADMIN = 0x00000400,
        POLICY_LOOKUP_NAMES = 0x00000800,
        POLICY_NOTIFICATION = 0x00001000
    }

    internal class Win32Lsa
    {
        internal const UInt32 STATUS_SUCCESS = 0;

        [DllImport("advapi32.dll", EntryPoint = "LsaOpenPolicy", SetLastError = true, CharSet = CharSet.Auto,
        CallingConvention = CallingConvention.StdCall)]
        internal extern static UInt32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
        UInt32 DesiredAcces, out IntPtr PolicyHandle);

        [DllImport("advapi32.dll", EntryPoint = "LsaClose", SetLastError = true, CharSet = CharSet.Auto,
        CallingConvention = CallingConvention.StdCall)]
        internal extern static UInt32 LsaClose(IntPtr PolicyHandle);

        [DllImport("advapi32.dll", EntryPoint = "LsaFreeMemory", SetLastError = true, CharSet = CharSet.Auto,
        CallingConvention = CallingConvention.StdCall)]
        internal extern static UInt32 LsaFreeMemory(IntPtr Buffer);

        [DllImport("advapi32.dll", EntryPoint = "LsaAddAccountRights", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern UInt32 LsaAddAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, int CountOfRights);

        [DllImport("advapi32.dll", EntryPoint = "LsaRemoveAccountRights", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern UInt32 LsaRemoveAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, bool AllRights,LSA_UNICODE_STRING[] UserRights, int CountOfRights);

        [DllImport("advapi32.dll", EntryPoint = "LsaEnumerateAccountRights", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern UInt32 LsaEnumerateAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, out IntPtr UserRights, out int CountOfRights);

        [DllImport("advapi32.dll", EntryPoint = "LsaEnumerateAccountsWithUserRight", SetLastError = true, CharSet = CharSet.Auto,
        CallingConvention = CallingConvention.StdCall)]
        internal extern static UInt32 LsaEnumerateAccountsWithUserRight(IntPtr PolicyHandle, ref LSA_UNICODE_STRING UserRights,
            out IntPtr EnumerationBuffer,
            out UInt32 CountReturned);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern bool LookupAccountSid(string lpSystemName, IntPtr Sid,
            [Out] StringBuilder name, ref int cbName,
            [Out] StringBuilder ReferencedDomainName, ref int cbReferencedDomainName, out int peUse);

        [DllImport("advapi32.dll", EntryPoint = "ConvertSidToStringSid", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
        internal static extern bool ConvertSidToStringSid(
            IntPtr lpSid,
            out string lpStringSid);

        [DllImport("advapi32.dll", EntryPoint = "ConvertStringSidToSid", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
        internal static extern bool ConvertStringSidToSid(
            string lpStringSid,
            ref IntPtr lpSid);

        [DllImport("advapi32.dll", EntryPoint = "FreeSid", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern void FreeSid(IntPtr pSid);

        [DllImport("advapi32.dll", EntryPoint = "LsaNtStatusToWinError", SetLastError = true, CharSet = CharSet.Auto,
        CallingConvention = CallingConvention.StdCall)]
        internal extern static UInt32 LsaNtStatusToWinError(UInt32 Status);
    }
}